package thread.cas;

import java.util.concurrent.atomic.AtomicInteger;

import sun.misc.Unsafe;

/**
 * @author jiangwz
 * @create 2019/9/13.
 */
public class CasDemo {

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    static AtomicInteger atomicInteger = new AtomicInteger(5);

    /**
     * CAS原理
     * 以 atomicInteger.getAndIncrement(); 方法讲解
     * 底层调用的是 unsafe.getAndAddInt(this, valueOffset, 1);
     * 其中 this 是 atomicInteger 对象,  valueOffset 是 5 这个值在内存中的偏移值,  1 是要加的值
     *
     * unsafe.getAndAddInt 会调用 一下方法  (以下方法在Unsafe类 358行)
     *
     * public final int getAndAddInt(Object var1, long var2, int var4) {
     *     int var5;
     *     do {
     *         var5 = this.getIntVolatile(var1, var2);
     *     } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
     *
     *     return var5;
     * }
     *
     * 以上方法就是CAS的核心
     * var1 就是 atomicInteger 对象
     * var2 就是 valueOffset 偏移值
     * var4 就是要增加的值
     * var5 内存中的值
     * 先进行do-while循环
     * 取到 atomicInteger对象在内存中 valueOffset的值
     * 然后利用 compareAndSwapInt 方法去内存地址中判断有没有被其他线程更改,
     * 如果没有被更新则更新成功,返回 getAndIncrement 这个方法的值
     * 如果被更新了,则compareAndSwapInt 返回false,继续do-while循环,重新获取最新的var5(因为是volatile,所以线程之间是可见的),直至更新成功为止.
     * 这就是CAS原理  compareAndSwapInt是jdk调用C的方法写的 该方法就是原子的
     *
     *
     * CAS的缺点  (synchronized 一致性保证,并发性下降,CAS 不加锁,并发性抢,保证一致性,需要多次比较)
     * 1.循环时间长,如果CAS长时间不成功,可能非常耗CPU
     * 2.只能保证一个值得原子性,不能保证多个对象(synchronized 可以保证整个方法都是原子性)
     * 3.ABA问题(这个最主要)    加版本号解决  juc里面有 AtomicStampedReference<V> 可以加时间戳或版本号等
     *
     *
     * @param args
     */

    public static void main(String[] args){


        System.out.println(atomicInteger.compareAndSet(5, 2019) + " value = " + atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(5, 1024) + " value = " + atomicInteger.get());
        atomicInteger.getAndIncrement();
    }
}
